package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"watermill-order-demo/internal/pubsub"
	"watermill-order-demo/pkg/events"

	"github.com/ThreeDotsLabs/watermill"
	"github.com/ThreeDotsLabs/watermill/message"
)

// InventoryStore 简单的内存库存结构体，存储各 SKU 的库存数量
// stock: SKU 到库存数量的映射
type InventoryStore struct {
	stock map[string]int
}

// NewInventoryStore 初始化库存，预设三种 SKU 的库存
func NewInventoryStore() *InventoryStore {
	return &InventoryStore{
		stock: map[string]int{
			"sku-1": 100,
			"sku-2": 50,
			"sku-3": 10,
		},
	}
}

// Reserve 预留库存，若库存不足则返回错误
func (s *InventoryStore) Reserve(items []events.Item) error {
	for _, it := range items {
		available := s.stock[it.SKU]
		if available < it.Qty {
			return fmt.Errorf("not enough stock for sku %s: need %d, have %d", it.SKU, it.Qty, available)
		}
	}
	for _, it := range items {
		s.stock[it.SKU] -= it.Qty
	}
	return nil
}

// main 库存服务入口，负责初始化消息通道、库存、事件路由和优雅退出
func main() {
	logger := watermill.NewStdLogger(true, true)

	// 创建内存消息通道（GoChannel），用于本地演示
	publisher, subscriber := pubsub.MakeGoChannelPubSub(logger)

	inv := NewInventoryStore()
	// 初始化 Watermill Router，用于事件处理
	router, err := message.NewRouter(message.RouterConfig{}, logger)
	if err != nil {
		log.Fatalf("new router: %v", err)
	}

	// 添加事件处理器：订阅 orders.created，预留库存并发布 inventory.reserved
	router.AddHandler(
		"inventory_reserve_handler",
		"orders.created", // 订阅订单创建事件
		subscriber,
		"inventory.reserved", // 发布库存预留事件
		publisher,
		func(msg *message.Message) ([]*message.Message, error) {
			var oc events.OrderCreated
			if err := json.Unmarshal(msg.Payload, &oc); err != nil {
				logger.Error("unmarshal order created", err, nil)
				return nil, err
			}
			logger.Info("inventory: received order", map[string]interface{}{"order_id": oc.OrderID, "items": oc.Items})

			// 预留库存
			if err := inv.Reserve(oc.Items); err != nil {
				logger.Error("reserve failed", err, map[string]interface{}{"order_id": oc.OrderID})
				return nil, err
			}

			// 预留成功，发布库存预留事件
			reserved := events.InventoryReserved{
				OrderID:    oc.OrderID,
				ReservedAt: time.Now().UTC(),
			}
			out, err := events.EncodeInventoryReserved(reserved)
			if err != nil {
				logger.Error("encode inventory reserved", err, nil)
				return nil, err
			}
			logger.Info("inventory reserved", map[string]interface{}{"order_id": oc.OrderID})
			return []*message.Message{out}, nil
		},
	)

	// 可添加中间件（如 recoverer、retry），此处省略
	router.AddMiddleware(
	// default middlewares could be added here (watermill middleware packages), omitted for brevity
	)

	ctx := context.Background()
	go func() {
		if err := router.Run(ctx); err != nil {
			log.Fatalf("router run: %v", err)
		}
	}()

	fmt.Println("Inventory service started. Waiting for messages...")
	// 优雅退出，监听 SIGINT/SIGTERM 信号
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	<-sig
	fmt.Println("Inventory service shutting down.")
}
